/*
 * analisador.cpp
 *
 *  Created on: 08/10/2012
 *      Author: wx
 */
#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;
#include "token.h"
#include "analisador.h"

analisador::analisador(string arquivo) {
	this->arquivo = arquivo;
	this->contchar = 0;
	this->tamlinha = 0;
	erro = false;
	carregar_reservadas();
}

void analisador::carregar_reservadas() {
	token toktemp;
	string temp;
	ifstream arquivopalavras("palavras_r.txt");

	while (!arquivopalavras.eof()) {
		temp = "";
		arquivopalavras >> temp;
		toktemp.setNome(temp);
		toktemp.stringtoclasse("palavra_reservada");
		reservadas.push_back(toktemp);
		//toktemp.print();
	}
	arquivopalavras.close();
}

int analisador::processar() {
	ifstream arquivo(this->arquivo.c_str());
	char guardalinha[128];
	token token;
	linhaatual = 1;

	while (arquivo.eof() != true) {
		arquivo.getline(guardalinha, 128);
		token_linha(guardalinha);
		guardalinha[0] = '\0';
		linhaatual++;
		cout << "\n";
	}
	return 0;
}

void analisador::token_linha(string linha) {
	this->tamlinha = linha.size();
	char c;

	for (contchar = 0; contchar < tamlinha;) {

		c = linha[contchar];

		/* comentarios */
		if (c == '{') {
			consumircomentario(linha);
		}
		///
		if (c == '/') {
			cout << c;
			if (linha[contchar+1] == '*') {
				cout << linha[contchar];
				consumircomentario(linha);
			} else {
				consumirsimbsimples(linha);
			}
		} else if (isdigit(c)) // fim tratamento de comentarios
			consumirnumero(linha);
		// consumir identificador/reservada
		else if (isalpha(c) || c == '$')
			montartoken(linha);
		///
		else if (c == '<') {
			if (linha[contchar + 1] == '=') {
				consumirduplo('<', linha);
			} else if (linha[contchar + 1] == '>') {
				consumirduplo('<', linha);
			} else
				consumirsimbsimples(linha);
		} ///
		else if (c == ':') {
			if (linha[contchar + 1] == '=') {
				consumirduplo(':', linha);
			} else
				consumirsimbsimples(linha);
		} else if (c == '>') {
			if (linha[contchar + 1] == '=') {
				consumirduplo('>', linha);
			} else
				consumirsimbsimples(linha);
		}
		// consumir simbolo simples
		else if ((c == '=') || (c == '+') || (c == ';') || (c == '(')
				|| (c == '*') || (c == ',') || (c == ')') || (c == '-')
				|| (c == '.')) {
			consumirsimbsimples(linha);
		} else if (c == ' ' || c == '	' || c == '\0') {
			contchar++;
		} else {
			consumirdesconhecido(linha);

		}
	}
}

int analisador::consumircomentario(string linha) {
	bool estrela = false;

	if (linha[contchar] == '{') {
		while (linha[contchar] != '}') {
			cout << linha[contchar];
			contchar++;
			if (linha[contchar] == '\0') {
				return 0;
			}
		}
	} else
		while (!(estrela && linha[contchar] != '/')) {
			cout << linha[contchar];
			contchar++;
			if (linha[contchar] == '\0') {
				return 0;
			}
			if (linha[contchar] == '*') {
				estrela = true;
			} else {
				estrela = false;
			}
		}
	cout << linha[contchar];
	contchar++;
	return 0;
}

int analisador::consumirnumero(string linha) {
	string novotoken = "";
	int coluna = contchar;

	coluna++;
	while (isdigit(linha[contchar])) {
		novotoken += linha[contchar];
		contchar++;
	}
	novotok.stringtoclasse("inteiro");
	if (linha[contchar] == ',') {
		novotoken += linha[contchar];
		contchar++;
		while (isdigit(linha[contchar])) {
			novotoken += linha[contchar];
			contchar++;
		}
		novotok.stringtoclasse("real");
	}
	novotok.setNome(novotoken);
	novotok.setLinha(linhaatual);
	novotok.setCol(coluna);

	listatoken.push_back(novotok);
	novotok.print();

	return 0;
}

int analisador::montartoken(string linha) {
	string novotoken = "";
	int coluna = contchar;

	coluna++;
	novotoken += linha[contchar];
	contchar++;
	while (isalnum(linha[contchar])) {
		novotoken += linha[contchar];
		contchar++;
	}
	novotok.setNome(novotoken);
	novotok.setCol(coluna);
	novotok.setLinha(linhaatual);
	if (buscareservada(novotok)) {
		novotok.stringtoclasse("palavra_reservada");
	} else
		novotok.stringtoclasse("identificador");
	novotok.print();
	listatoken.push_back(novotok);
	return 0;
}

bool analisador::buscareservada(token amostra) {
	unsigned int i = 0;
	token temp;

	while (i < reservadas.size()) {
		temp = reservadas[i];

		if (temp.nomeigual(amostra)) {
			return true;
		}
		i++;
	}
	return false;
}

int analisador::consumirsimbsimples(string linha) {
	char c = linha[contchar];
	string token = "";
	int coluna = contchar;

	coluna++;
	token += c;

	novotok.setNome(token);
	novotok.setLinha(linhaatual);
	novotok.setCol(coluna);
	novotok.stringtoclasse("simbsimples");
	contchar++;
	listatoken.push_back(novotok);
	novotok.print();
	return 0;
}

int analisador::consumirduplo(char b, string linha) {

	char c = linha[++contchar];
	string token = "";
	int coluna = contchar;

	coluna++;
	token += b;
	token += c;
	cout << token;
	novotok.setNome(token);
	novotok.setLinha(linhaatual);
	novotok.setCol(coluna);
	novotok.stringtoclasse("simbduplo");
	contchar++;
	listatoken.push_back(novotok);
	novotok.print();
	return 0;
}

void analisador::print(string nomearquivo) {
	unsigned int i = 0;
	token temp;
	ofstream pfile(nomearquivo.c_str());

	while (i < listatoken.size()) {
		temp = listatoken[i];
		pfile << temp.sprint();
		pfile << endl;
		i++;
	}
	pfile.close();
	gera_saida();

}

void analisador::consumirdesconhecido(string linha) {
	string token = "";
	int coluna = contchar;
	char c = linha[contchar];

	coluna++;

	while (!((c == '=') || (c == '+') || (c == ';') || (c == '(') || (c == '+')
			|| (c == ',') || (c == ')') || (c == '-') || (c == '.')
			|| (c == '\0') || (c == '$'))) {
		token += c;
		contchar++;
		c = linha[contchar];
	}
	if (token.size() > 0) {
		novotok.setNome(token);
		novotok.setLinha(linhaatual);
		novotok.setCol(coluna);
		novotok.stringtoclasse("desconhecido");
		listatoken.push_back(novotok);
		cerr << "Erro:" << '\n' << novotok.sprint() << endl;
		erro = true;
	}
}

void analisador::gera_saida() {
	unsigned int i = 0;
	token temp;
	saida_lexico = listatoken;
	cout << "gera saida";
	while (i < saida_lexico.size()) {
		temp = saida_lexico[i];
		cout << temp.sprint();
		cout << endl;
		i++;
	}
}

